﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Activation;

namespace SystemScanner.ServiceApplication
{
	[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
	public class ScanService : IScanService
	{
		public void ProcessScan(SystemScanner.Data.Computer computer, SystemScanner.Data.Scan scan)
		{
			/// In all cases below, the entities passed in ("computer" and "scan" plus their related entities) are all
			/// being recreated as completely new versions. This is because I couldn't get the entities that are passed
			/// in from the service call above to attach to the context below ("ctx") in a way where they were savable.
			/// The scan entity comes in with a whole crapload of related entities, many of which probably already 
			/// exist in the database. I tried various combinations of iterating through all the relations, taking the
			/// object graphs apart, reassembling them in different ways, etc., but nothing seemed to work.
			/// May be fixable with a bit of JFGI (http://www.urbandictionary.com/define.php?term=jfgi).

			using (var ctx = new SystemScanner.Data.SystemScanningEntities())
			{
				var newScan = new SystemScanner.Data.Scan
				{
					Performed = scan.Performed,
					ScannerVersion = scan.ScannerVersion
				};

				// See if the computer passed in already exists in the DB...
				var computerFromDB =
					(from c in ctx.Computers
					 where c.Hostname == computer.Hostname
					 && c.DomainName == computer.DomainName
					 select c).FirstOrDefault();

				// ... if it does, use it instead.
				if (computerFromDB == null)
				{
					ctx.AddToComputers(computer);
				}
				else
				{
					// If it did already exist, use the existing one instead. Make sure the Scan
					// is associated with THIS one, not the one that was passed in.
					computer = computerFromDB;
				}


				computer.Scans.Add(newScan);

				////////////////////////////////////////////////////
				// Service and ScanService
				////////////////////////////////////////////////////
				var allServicesFromDB = ctx.Services.ToList();
				foreach (var scanServiceFromCaller in scan.ScanServices)
				{
					var scanServiceToUse = EntityCopier.ScanServiceDeepCopy(scanServiceFromCaller);

					var serviceFromCaller = scanServiceFromCaller.Service;
					var serviceToUse = allServicesFromDB.Where(s => string.Compare(s.Identifier, serviceFromCaller.Identifier, true) == 0).FirstOrDefault();
					if (serviceToUse == null)
					{
						serviceToUse = EntityCopier.ServiceDeepCopy(serviceFromCaller);
					}

					scanServiceToUse.Service = serviceToUse;

					newScan.ScanServices.Add(scanServiceToUse);
				}

				////////////////////////////////////////////////////
				// Hotfix
				////////////////////////////////////////////////////
				var allHotfixesFromDB = ctx.Hotfixes.ToList();
				foreach (var hf in scan.Hotfixes)
				{
					var valueToAdd = allHotfixesFromDB.Where(h => string.Compare(h.Identifier, hf.Identifier, true) == 0).FirstOrDefault();
					if (valueToAdd == null)
					{
						valueToAdd = EntityCopier.HotfixDeepCopy(hf);
					}
					newScan.Hotfixes.Add(valueToAdd);
				}

				////////////////////////////////////////////////////
				// SoftwareApplication
				////////////////////////////////////////////////////
				var allSoftwareAppsFromDB = ctx.SoftwareApplications.ToList();
				foreach (var item in scan.SoftwareApplications)
				{
					var valueToAdd = allSoftwareAppsFromDB.Where(h => string.Compare(h.Identifier, item.Identifier, true) == 0).FirstOrDefault();
					if (valueToAdd == null)
					{
						valueToAdd = EntityCopier.SoftwareApplicationDeepCopy(item);
					}
					newScan.SoftwareApplications.Add(valueToAdd);
				}

				////////////////////////////////////////////////////
				// OperatingSystemComponents
				////////////////////////////////////////////////////
				var allOSComponentsFromDB = ctx.OperatingSystemComponents.ToList();
				foreach (var item in scan.OperatingSystemComponents)
				{
					var valueToAdd = allOSComponentsFromDB.Where(h => string.Compare(h.Identifier, item.Identifier, true) == 0).FirstOrDefault();

					if (valueToAdd == null)
					{
						valueToAdd = EntityCopier.OperatingSystemComponentDeepCopy(item);
						;
					}
					newScan.OperatingSystemComponents.Add(valueToAdd);
				}

				ctx.SaveChanges();
			}
		}
	}
}
